package cn.me.alphamq.common.remote;

import cn.me.alphamq.common.store.SyncFutureManager;
import cn.me.alphamq.common.entity.BaseMsg;
import cn.me.alphamq.common.enumeration.EventCodeEnum;
import cn.me.alphamq.common.msg.TcpMsg;
import cn.me.alphamq.common.util.NettyUtil;
import com.alibaba.fastjson2.JSON;
import io.netty.channel.Channel;
import io.netty.channel.SimpleChannelInboundHandler;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 使用 netty 远程访问的客户端
 *
 * @author f
 */
public class NettyClient {

    /**
     * 服务器的 ip 地址
     */
    private final String ip;

    /**
     * 服务器的端口号
     */
    private final Integer port;

    public NettyClient(String address) {
        String[] split = address.split(":");
        this.ip = split[0];
        this.port = Integer.parseInt(split[1]);
    }

    public NettyClient(String ip, Integer port) {
        this.ip = ip;
        this.port = port;
    }

    /**
     * 与服务器连接的通道
     */
    private Channel channel;

    /**
     * 初始化连接
     *
     * @param clientName  客户端的名称
     * @param respHandler 服务器响应的处理器，要求是可共享的
     */
    public void initConnection(String clientName, SimpleChannelInboundHandler<TcpMsg> respHandler) {
        channel = NettyUtil.startNettyClient(
                ip,
                port,
                clientName,
                respHandler
        );
    }

    /**
     * 发送消息，并获取消息的响应结果
     *
     * @param eventCodeEnum 消息码值枚举
     * @param msg           发送的消息
     * @return 消息的响应结果
     */
    public TcpMsg sendMsgSync(EventCodeEnum eventCodeEnum, BaseMsg msg) {
        return sendMsgSync(eventCodeEnum, UUID.randomUUID().toString(), msg);
    }

    /**
     * 发送消息，并获取消息的响应结果
     *
     * @param eventCodeEnum 消息码值枚举
     * @param msgId         消息的 id
     * @param msg           发送的消息
     * @return 消息的响应结果
     */
    public TcpMsg sendMsgSync(EventCodeEnum eventCodeEnum, String msgId, BaseMsg msg) {
        msg.setMsgId(msgId);
        channel.writeAndFlush(new TcpMsg(eventCodeEnum, JSON.toJSONBytes(msg)));

        SyncFuture syncFuture = new SyncFuture(msgId);
        SyncFutureManager.put(msgId, syncFuture);

        try {
            // 最多等待 3s TODO 可以使用文件来配置最长等待时间
            return syncFuture.get(3000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 发送消息，不获取消息的响应结果
     *
     * @param eventCodeEnum 消息码值枚举
     * @param msg           发送的消息
     */
    public void sendMsgAsync(EventCodeEnum eventCodeEnum, BaseMsg msg) {
        channel.writeAndFlush(new TcpMsg(eventCodeEnum, JSON.toJSONBytes(msg)));
    }

    /**
     * 关闭通道
     */
    public void close() {
        channel.close();
    }
}
